#include "SQL.h"

/*
功能：创建或打开数据库
参数：
    const char *path：数据库地址
返回值：返回创建的数据库
*/
sqlite3 *creat_SQL(const char *path)
{
    sqlite3 *db;                              // 创建数据库句柄
    if (sqlite3_open(path, &db) != SQLITE_OK) // 打开数据库
    {
        fprintf(stderr, "open err:%s\n", sqlite3_errmsg(db)); // 错误信息
        return NULL;
    }
    return db;
}

/*
功能：创建或打开病人库
参数：
    sqlite3 *db：创建的数据库
返回值：
    0 创建或打开病人库成功
    -1 创建或打开病人库失败
*/
int creat_patientDB(sqlite3 **db)
{
    *db = creat_SQL("../patient.db");
    if (*db == NULL)
    {
        return -1;
    }
    return 0;
}

/*
功能：创建或打开病房库
参数：
    sqlite3 *db：创建的数据库
返回值：
    0 创建或打开病房库成功
    -1 创建或打开病房库失败
*/
int creat_roomDB(sqlite3 **db)
{
    *db = creat_SQL("../room.db");
    if (*db == NULL)
    {
        return -1;
    }
    return 0;
}

/*
功能：创建或打开用户库
参数：
    sqlite3 *db：创建的数据库
返回值：
    0 创建或打开用户库成功
    -1 创建或打开用户库失败
*/
int creat_userDB(sqlite3 **db)
{
    *db = creat_SQL("../user.db");
    if (*db == NULL)
    {
        return -1;
    }
    return 0;
}

/*
功能：在指定数据库中创建数据表
参数：
    sqlite3 *db：指定的数据库
    char *table：数据表信息
返回值：
    0 创建数据表成功
    -1 创建数据表失败
*/

int creat_table(sqlite3 *db, char *table)
{
    char *errmsg = NULL;     // 错误信息
    char sql[SQLSIZE] = {0}; // sql命令

    if (strcmp(table, "patientID") == 0)
    {
        // 创建表的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "create table if not exists %s (patientID int primary key)", table);
        printf("sql命令：%s\n", sql);
    }
    else if (strncmp(table, "patient", 7) == 0)
    {
        // 创建表的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "create table if not exists %s (patientID int,patientName char,patientAge int,patientGender int, illness char, roomID int, heart_rate float, O2 float, doctorID int,doctorName char, time char)", table);
        printf("sql命令：%s\n", sql);
    }
    else if (strncmp(table, "room", 4) == 0)
    {
        // 创建表的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "create table if not exists %s (roomID int, temperature float,\
        humidity float, infrared int, flame int, call int, time char)",
                table);
        printf("sql命令：%s\n", sql);
    }
    else if (strcmp(table, "user") == 0)
    {
        // 创建表的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "create table if not exists user (username char, password char,authority int)");
        printf("sql命令：%s\n", sql);
    }
    else
    {
        // 不是选定的表的话就返回-1
        printf("Not Find Table");
        return -1;
    }

    int ret = 0;
    if (ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0) // 调用sql命令
    {
        printf("创建表失败\nret = %d\n", ret);
        fprintf(stderr, "create err:%s\n", sqlite3_errmsg(db)); // 生成错误信息
        if (errmsg != NULL)
        {
            sqlite3_free(errmsg);
        }
        return -1;
    }
    printf("创建/打开表成功\n");
    return 0;
}

/*
功能：创建病人表
参数：
    sqlite3 *db：创建的数据库
    int patientID：病人ID
返回值：
    0 创建病人表成功
    -1 创建病人表失败
*/
int creat_patientTable(sqlite3 *db, int patientID)
{
    char table[32] = {0};
    sprintf(table, "patient_%d", patientID);
    printf("table name patient_%d\n", patientID);
    return creat_table(db, table);
}

/*
功能：创建病人ｉｄ表
参数：
    sqlite3 *db：创建的数据库
返回值：
    0 创建病人ｉｄ表成功
    -1 创建病人ｉｄ表失败
*/
int creat_patientIDTable(sqlite3 *db)
{
    return creat_table(db, "patientID");
}

/*
功能：创建病房表
参数：
    sqlite3 *db：创建的数据库
    int roomID：病房号
返回值：
    0 创建病房表成功
    -1 创建病房表失败
*/
int creat_roomTable(sqlite3 *db, int roomID)
{
    char table[32] = {0};
    sprintf(table, "room_%d", roomID);
    return creat_table(db, table);
}

/*
功能：创建用户表
参数：
    sqlite3 *db：创建的数据库
返回值：
    0 创建用户表成功
    -1 创建用户表失败
*/
int creat_userTable(sqlite3 *db)
{
    printf("创建用户表\n");
    return creat_table(db, "user");
}

/*
功能：向数据表中插入信息
参数：
    sqlite3 *db：操作的数据库
    char *table：操作的表
    void *data：写入数据的结构体
返回值：
    0 插入数据成功
    -1　插入数据失败
*/
int insert_values(sqlite3 *db, char *table, void *data)
{
    char *errmsg = NULL;     // 错误信息
    char sql[SQLSIZE] = {0}; // ｓｑｌ命令
    if (strcmp(table, "patientID") == 0)
    {
        int *patientID = data;
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "insert into patientID values(%d)", *patientID);
    }
    else if (strncmp(table, "patient", 7) == 0)
    {
        patient_t *patient = data;
        // 插入数据的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "insert into patient_%d values(%d,'%s',%d,%d,'%s',%d,%.2f,%.2f, %d,'%s','%s')", patient->patientID,patient->patientID,
                patient->patientName, patient->patientAge, patient->patientGender, patient->illness,
                patient->roomID, patient->heart_rate, patient->O2, patient->doctorID, patient->doctorName, patient->time);
    }
    else if (strncmp(table, "room", 4) == 0)
    {
        room_t *room = data;
        // 插入数据的命令
        memset(sql, 0, SQLSIZE);
        sprintf(sql, "insert into room values(%d,%.2f,%.2f, %d, %d, %d, '%s')", room->roomID,
                room->temperature, room->humidity, room->infrared, room->flame, room->call, room->time);
    }
    else if (strcmp(table, "user") == 0)
    {
        user_t *user = data;
        memset(sql, 0, SQLSIZE);
        // 插入数据的命令
        sprintf(sql, "insert into user values('%s', '%s', %d)", user->username, user->password, user->authority);
    }
    else
    {
        // 不是选定的表的话就返回－１
        printf("Not Find Table");
        return -1;
    }

    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0) // 调用ｓｑｌ命令
    {
        fprintf(stderr, "insert err:%s\n", errmsg); // 错误信息
        if (errmsg != NULL)
        {
            sqlite3_free(errmsg);
        }
        return -1;
    }
    return 0;
}

/*
功能：向病人表中插入信息
参数：
    sqlite3 *db：操作的数据库
    cJSON *data：传入的json数据
返回值：
    0 插入数据成功
    -1　插入数据失败
*/
int insert_patient(sqlite3 *db, std_node_t *data)
{
    // 从json中获取病人信息
    patient_t patient;
    for (int i = 0; i < 25; i++)
    {
        switch (data[i].key)
        {
        case 101:
            patient.patientID = data[i].new_val.i_val;
            break;
        case 102:
            strcpy(patient.patientName, data[i].new_val.str);
            break;
        case 103:
            patient.patientAge = data[i].new_val.i_val;
            break;
        case 104:
            patient.patientGender = data[i].new_val.i_val;
            break;
        case 105:
            strcpy(patient.illness, data[i].new_val.str);
            break;
        case 106:
            patient.heart_rate = data[i].new_val.f_val;
            break;
        case 107:
            patient.O2 = data[i].new_val.f_val;
            break;
        case 108:
            patient.roomID = data[i].new_val.i_val;
            break;
        case 109:
            patient.doctorID = data[i].new_val.i_val;
            break;
        case 110:
            strcpy(patient.doctorName, data[i].new_val.str);
            break;
        case 111:
            strcpy(patient.time, data[i].new_val.str);
            break;
        default:
            break;
        }
    }

    // 先判断病人ｉｄ是否存在
    char sql[SQLSIZE] = {0}; // sql命令
    char *buf = NULL;        // 接收查询结果
    char table[32] = {0};    // 创建或者打开的表名
    // 设置sql命令
    sprintf(sql, "select * from patientID where patientID = %d", patient.patientID);
    // 查询病人ID是否存在
    int ret = select_value(db, "patientID", sql, &buf);
    if (ret == 0) // 不存在则以病人ID创建病人表
    {
        // 将病人id存入病人id表
        insert_values(db, "patientID", &patient.patientID);
        creat_patientTable(db, patient.patientID);
        sprintf(table, "patient_%d", patient.patientID);
        return insert_values(db, table, &patient);
    }
    else if (ret == 1) // 存在则直接插入病人数据
    {
        sprintf(table, "patient_%d", patient.patientID);
        return insert_values(db, table, &patient);
    }
    else // 其他情况返回-1
    {
        return -1;
    }
}

/*
功能：向病房中插入信息
参数：
    sqlite3 *db：操作的数据库
    cJSON *data：传入的json数据
返回值：
    0 插入数据成功
    -1　插入数据失败
*/
int insert_room(sqlite3 *db, std_node_t *data)
{
    room_t room;
    for (int i = 0; i < 25; i++)
    {
        switch (data[i].key)
        {
        case 201:
            room.roomID = data[i].new_val.i_val;
            break;
        case 202:
            room.temperature = data[i].new_val.f_val;
            break;
        case 203:
            room.humidity = data[i].new_val.f_val;
            break;
        case 204:
            room.infrared = data[i].new_val.i_val;
            break;
        case 205:
            room.flame = data[i].new_val.i_val;
            break;
        case 206:
            room.call = data[i].new_val.i_val;
            break;
        case 207:
            strcpy(room.time, data[i].new_val.str);
            break;
        case 208:
            room.ozone = data[i].new_val.i_val;
            break;
        case 209:
            room.ultraviolet = data[i].new_val.i_val;
            break;
        case 210:
            room.fan = data[i].new_val.i_val;
            break;
        case 211:
            room.sprayer = data[i].new_val.i_val;
            break;
        default:
            break;
        }
    }

    // 先判断病房号是否存在
    char sql[SQLSIZE] = {0}; // sql命令
    char *buf = NULL;        // 接收查询结果
    char table[32] = {0};    // 创建或者打开的表名
    // 设置sql命令
    sprintf(sql, "select * from roomID where roomID = %d", room.roomID);
    // 查询病房号是否存在
    int ret = select_value(db, "roomID", sql, &buf);
    if (ret == 0) // 不存在则以病房号创建病房表
    {
        creat_roomTable(db, room.roomID);
        sprintf(table, "room_%d", room.roomID);
        return insert_values(db, table, &room);
    }
    else if (ret == 1) // 存在则直接插入病房数据
    {
        sprintf(table, "room_%d", room.roomID);
        return insert_values(db, table, &room);
    }
    else // 其他情况返回-1
    {
        return -1;
    }
}

/*
功能：向用户表中插入信息
参数：
    sqlite3 *db：操作的数据库
    std_node_t *data：传入的json数据
返回值：
    0 插入数据成功
    -1　插入数据失败
*/
int insert_user(sqlite3 *db, std_node_t *data)
{
    user_t user;

    for (int i = 22; i < 25; i++)
    {
        switch (data[i].key)
        {
        case 301:
            strcpy(user.username, data[i].new_val.str);
            break;
        case 302:
            strcpy(user.password, data[i].new_val.str);
            break;
        case 303:
            user.authority = data[i].new_val.i_val;
            break;
        default:
            break;
        }
    }
    printf("username = %s\n", user.username);
    printf("password = %s\n", user.password);
    printf("authority = %d\n", user.authority);
    return insert_values(db, "user", &user);
}

/*
功能：查找某数据
参数：
    sqlite3 *db：查找的数据库
    char *table：查找的数据表
    char *string：查找的字符串，要求符合ＳＱＬ命令
    char *buf：存放查找到的数据
返回值：
    >0：查找到的信息条数
    0：查找到０条信息
    -1：未找到信息
*/
int select_value(sqlite3 *db, char *table, char *sql, char **result)
{
    if (db == NULL || table == NULL)
    {
        return -1;
    }
    char *errmsg = NULL; // 错误信息
    int row, column;     // 行和列
    if (sql == NULL)
    {
        return -1;
    }
    printf("开始检查数据库是否存在数据\n");
    if (sqlite3_get_table(db, sql, &result, &row, &column, &errmsg) != 0)
    {
        fprintf(stderr, "select err:%s\n", errmsg); // 错误信息
        return -1;
    }
    printf("检查数据库是否存在数据完成\n");
    return row;
}

/*
功能：修改数据库中信息
参数：
    sqlite3 *db：操作的数据库
    char *table：操作的表
    char *string：修改的字符串，要求符合ＳＱＬ命令
返回值：
    0 修改数据成功
    -1 修改数据失败
*/
int update_value(sqlite3 *db, char *table, char *string)
{
    char *errmsg = NULL;     // 错误信息
    char sql[SQLSIZE] = {0}; // sql命令
    int update = sqlite3_exec(db, string, NULL, NULL, &errmsg);
    if (update != 0)
    {
        fprintf(stderr, "update err:%s\n", errmsg); // 错误信息
        return -1;
    }
    return 0;
}

/*
功能：修改用户密码
参数：
    sqlite3 *db：操作的数据库
    char *username：用户名
    char *password：密码
返回值：
    0 修改密码成功
    -1 修改密码失败
*/
int update_password(sqlite3 *db, char *username, char *password)
{
    char sql[SQLSIZE] = {0}; // sql命令
    sprintf(sql, "password = '%s' where username = '%s'", password, username);
    return update_value(db, "user", sql);
}

void check_system_memory()
{
// 在 Linux/Unix 系统下可以检查内存状态
#ifdef __unix__
    FILE *meminfo = fopen("/proc/meminfo", "r");
    if (meminfo)
    {
        char line[256];
        while (fgets(line, sizeof(line), meminfo))
        {
            printf("%s", line);
        }
        fclose(meminfo);
    }
#endif
}